package com.tbit.uqbike.client.aop;

import com.tbit.uqbike.client.constant.annotation.PreventDuplication;
import com.tbit.uqbike.client.exception.BaseException;
import com.tbit.uqbike.client.service.RedisService;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * @Author: chen
 * @Description: 接口频次限制
 * @Date: 创建于 10:38 2021/9/28
 */
@Component
@Aspect
public class PreventDuplicationAspect {

    @Autowired
    private RedisService redisService;

    /**
     * 定义切点
     */
    @Pointcut("@annotation(com.tbit.uqbike.client.constant.annotation.PreventDuplication)")
    public void preventDuplication() {
    }

    /**
     * 环绕通知 （可以控制目标方法前中后期执行操作，目标方法执行前后分别执行一些代码）
     *
     * @param joinPoint
     * @return
     */
  /*@Around("preventDuplication()")
  public Object before(ProceedingJoinPoint joinPoint) throws Exception {
    ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
        .getRequestAttributes();
    HttpServletRequest request = attributes.getRequest();
    HttpServletResponse response= attributes.getResponse();
    Assert.notNull(request, "request cannot be null.");
    //获取执行方法
    Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
    //获取防重复提交注解
    PreventDuplication annotation = method.getAnnotation(PreventDuplication.class);

    //获取方法名称
    Signature signature = joinPoint.getSignature();

    if (!(signature instanceof MethodSignature)) {
      throw new RuntimeException("该注解只支持方法");
    }
    MethodSignature methodSignature = (MethodSignature) signature;

    String[] params = methodSignature.getParameterNames();
    Object[] args = joinPoint.getArgs();
    Boolean ble =false;
    for (int i=0;i<args.length;i++){
      if("ble".equals(params[i])){
        String bleString= String.valueOf(args[i]);
        if(bleString!=null){
          ble=Boolean.valueOf(bleString);
        }
      }
    }
    String[] parameterNames = ((MethodSignature) signature).getParameterNames();
    // 获取token的下标
    int tokenIndex = ArrayUtils.indexOf(parameterNames, "token");
    // 获取token以及方法标记，生成redisKey和redisValue
    *//*Object[] args = joinPoint.getArgs();*//*
    String token= String.valueOf(args[tokenIndex]);

    String className = joinPoint.getTarget().getClass().getName();
    className=className.substring(className.lastIndexOf("."));
    String pointName =signature.getName();
    String redisKey = "unique."+token+className+"."+pointName;
    String redisValue = "1";
    if (redisService.get(redisKey)==null||ble) {
      //设置防重复操作限时标记（前置通知）
      redisService.add(redisKey, redisValue, (int)annotation.expireSeconds());
      *//*redisTemplate.opsForValue()
          .set(redisKey, redisValue, annotation.expireSeconds(), TimeUnit.SECONDS);*//*
      try {
        //正常执行方法并返回
        //ProceedingJoinPoint类型参数可以决定是否执行目标方法，且环绕通知必须要有返回值，返回值即为目标方法的返回值
        return joinPoint.proceed();
      } catch (Throwable throwable) {
        throwabllog.error(e.getMessage(), e);
        //确保方法执行异常实时释放限时标记(异常后置通知)
        redisService.del(redisKey);
        //redisTemplate.delete(redisKey);
        ResponseUtil.print(response, "{\"ret\":0,\"code\":\" -102\",\"msg\":\"请勿重复操作\"}");
        //throw new Exception(throwable);
      }
    } else {
      ResponseUtil.print(response, "{\"ret\":0,\"code\":\"-102\",\"msg\":\"请勿重复操作\"}");
      //throw new DuplicationException();
    }
    return false;
  }*/
    @Before("preventDuplication()")
    public void before(JoinPoint joinPoint) throws Exception {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        HttpServletResponse response = attributes.getResponse();
        Assert.notNull(request, "request cannot be null.");
        //获取执行方法
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        //获取防重复提交注解
        PreventDuplication annotation = method.getAnnotation(PreventDuplication.class);

        //获取方法名称
        Signature signature = joinPoint.getSignature();

        if (!(signature instanceof MethodSignature)) {
            throw new RuntimeException("该注解只支持方法");
        }
        MethodSignature methodSignature = (MethodSignature) signature;

        String[] params = methodSignature.getParameterNames();
        Object[] args = joinPoint.getArgs();
        Boolean ble = false;
        boolean useWxzff=false;
        for (int i = 0; i < args.length; i++) {
            if ("ble".equals(params[i])) {
                String bleString = String.valueOf(args[i]);
                if (bleString != null) {
                    ble = Boolean.valueOf(bleString);
                }
            }
            if ("useWxzff".equals(params[i])) {
                String useWxzffString = String.valueOf(args[i]);
                if ("0".equals(useWxzffString)) {
                    useWxzff = true;
                }
            }
        }
        if (ble||useWxzff) {
            return;
        }
        String[] parameterNames = ((MethodSignature) signature).getParameterNames();
        // 获取token的下标
        int tokenIndex = ArrayUtils.indexOf(parameterNames, "token");
        // 获取token以及方法标记，生成redisKey和redisValue
        /*Object[] args = joinPoint.getArgs();*/
        String token = String.valueOf(args[tokenIndex]);

        String className = joinPoint.getTarget().getClass().getName();
        className = className.substring(className.lastIndexOf("."));
        String pointName = signature.getName();
        String redisKey = "unique." + token + className + "." + pointName;
        String redisValue = "1";
        if (redisService.get(redisKey) == null) {
            //设置防重复操作限时标记（前置通知）
            redisService.add(redisKey, redisValue, (int) annotation.expireSeconds());
        } else {
            throw new BaseException("-102", "请勿重复操作");
            // ResponseUtil.print(response, "{\"ret\":0,\"code\":\"-102\",\"msg\":\"请勿重复操作\"}");
        }

    }

}
